package com.xuecheng.media.jobhandler;


import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.MediaFileProcessService;
import com.xuecheng.media.service.MediaFileService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.apache.ibatis.logging.log4j2.Log4j2LoggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * XxlJob开发示例（Bean模式）
 *
 * 开发步骤：
 *      1、任务开发：在Spring Bean实例中，开发Job方法；
 *      2、注解配置：为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")"，注解value值对应的是调度中心新建任务的JobHandler属性的值。
 *      3、执行日志：需要通过 "XxlJobHelper.log" 打印执行日志；
 *      4、任务结果：默认任务结果为 "成功" 状态，不需要主动设置；如有诉求，比如设置任务结果为失败，可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果；
 *
 * @author xuxueli 2019-12-11 21:52:51
 */
@Component
public class SampleXxlJob {
    @Autowired
    MediaFileProcessService mediaFileProcessService;
    @Autowired
    MediaFileService mediaFileService;
    private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);
    //ffmpeg的路径
    String ffmpeg_path = "D:\\学成在线所需工具\\ffmpeg\\ffmpeg.exe";//ffmpeg的安装位置

    /**
     * 2、分片广播任务
     */
    @XxlJob("videoJobHandler")
    public void videoJobHandler() throws Exception {
        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex();
        int shardTotal = XxlJobHelper.getShardTotal();
        //确定cpu的核心数
        int processors = Runtime.getRuntime().availableProcessors();
        List<MediaProcess> mediaProcessList = mediaFileProcessService.getMediaProcessList( shardTotal,shardIndex, processors);
        int size = mediaProcessList.size();
        if (size<0){
            return;
        }
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(size);
        //创建计数器
        CountDownLatch countDownLatch = new CountDownLatch(size);
        mediaProcessList.forEach(mediaProcess -> {
            executorService.execute(()->{
                try {
                    //获取任务id
                    Long taskId = mediaProcess.getId();
                    //获取md5值
                    String fileId = mediaProcess.getFileId();
                    //开启任务(获得锁)
                    boolean b = mediaFileProcessService.startTask(taskId);
                    if (!b){
                        mediaFileProcessService.saveProcessFinishStatus(taskId,"3",fileId,null,"获得锁失败");
                        //获得锁失败
                        return;
                    }
                    //获取桶
                    String bucket = mediaProcess.getBucket();
                    //获取路径
                    String objectName = mediaProcess.getFilePath();
                    //获取源文件名
                    String filename = mediaProcess.getFilename();
                    File file = mediaFileService.downloadFileFromMinIO(bucket, objectName);
                    if (file==null){
                        System.err.println("下载文件出错");
                        mediaFileProcessService.saveProcessFinishStatus(taskId,"3",fileId,null,"下载文件出错");
                        return;
                    }
                    //执行转码
                    //源avi视频的路径
                    String absolutePath = file.getAbsolutePath();
                    //转换后mp4文件的名称
                    String mp4_name =mediaFileService.getFilePathBymd5(fileId,".mp4");
                    //转换后mp4文件的路径
                    File mp4File =null;
                    try {
                         mp4File = File.createTempFile("minio", ".mp4");
                    } catch (IOException e) {
                        System.err.println("创建临时文件异常");
                        mediaFileProcessService.saveProcessFinishStatus(taskId,"3",fileId,null,"创建临时文件异常");
                        return;
                    }
                    //创建工具类对象
                    Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmpeg_path,absolutePath,mp4_name,mp4File.getAbsolutePath());
                    //开始视频转换，成功将返回success
                    String result = videoUtil.generateMp4();
                    if (!result.equals("success")){//任务执行失败
                        mediaFileProcessService.saveProcessFinishStatus(taskId,"3",fileId,null,"视频转换失败");
                    }
                    //上传到minio
                    boolean b1 = mediaFileService.addMediaFilesToMinIO(mp4File.getAbsolutePath(), "video/mp4", bucket, mp4_name);
                    if (!b1){
                        mediaFileProcessService.saveProcessFinishStatus(taskId,"3",fileId,null,"上传视频失败");
                        return;
                    }
                    //获取url
                    String url = getFilePathBymd5(fileId, ".mp4");
                    //保存处理结果
                    mediaFileProcessService.saveProcessFinishStatus(taskId,"2",fileId,url,null);
                } finally {
                        countDownLatch.countDown();
                }
            });
        });
        //等待给一个富裕的时间兜底等待，让线程里try的代码全部执行完后结束方法否则阻塞
        countDownLatch.await(30,TimeUnit.MINUTES);
    }
    public String getFilePathBymd5(String fileMd5, String fileExt) {
        return fileMd5.substring(0, 1) + "/" + fileMd5.substring(1, 2) + "/" + fileMd5 + "/" + fileMd5 + fileExt;
    }

}
